package com.zrrd.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zrrd.common.constants.WemediaConstants;
import com.zrrd.common.exception.CustomException;
import com.zrrd.model.common.dtos.PageResponseResult;
import com.zrrd.model.common.dtos.ResponseResult;
import com.zrrd.model.common.enums.AppHttpCodeEnum;
import com.zrrd.model.wemedia.dtos.WmNewsDto;
import com.zrrd.model.wemedia.dtos.WmNewsPageReqDto;
import com.zrrd.model.wemedia.pojos.WmMaterial;
import com.zrrd.model.wemedia.pojos.WmNews;
import com.zrrd.model.wemedia.pojos.WmNewsMaterial;
import com.zrrd.model.wemedia.pojos.WmUser;
import com.zrrd.utils.thread.WmThreadLocalUtil;
import com.zrrd.wemedia.mapper.WmMaterialMapper;
import com.zrrd.wemedia.mapper.WmNewsMapper;
import com.zrrd.wemedia.mapper.WmNewsMaterialMapper;
import com.zrrd.wemedia.service.WmNewsAutoScanService;
import com.zrrd.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author WanJl
 * @version 1.0
 * @title WmNewsServiceImpl
 * @description
 * @create 2023/9/21 15:53
 */
@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    WmMaterialMapper wmMaterialMapper;
    /**
     * 查询文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {
        //1.检查参数
        if (dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.分页参数检查
        dto.checkParam();
        //3.判断当前登录的自媒体用户是否存在，
        WmUser user = WmThreadLocalUtil.getUser();
        if (user==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }
        // ------以上完成各种验证---接下来开始进行分页查询-----
        IPage page=new Page(dto.getPage(),dto.getSize());
        //设置查询条件
        LambdaQueryWrapper<WmNews> lqw=new LambdaQueryWrapper<>();

        //设置状态的精确查询
        if (dto.getStatus()!=null){
            lqw.eq(WmNews::getStatus,dto.getStatus());
        }
        //设置频道精确查询
        if (dto.getChannelId()!=null){
            lqw.eq(WmNews::getChannelId,dto.getChannelId());
        }
        //设置时间范围查询
        if (dto.getBeginPubDate()!=null&&dto.getEndPubDate()!=null){
            lqw.between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }
        //设置关键字模糊查询
        if (StringUtils.isNotBlank(dto.getKeyword())){
            lqw.like(WmNews::getTitle,dto.getKeyword());
        }
        //以上----可选条件全部设置完成，下面开始设置必选条件
        //查询当前登录的用户的所有新闻文章
        lqw.eq(WmNews::getUserId,user.getId());
        //执行带有条件的分页查询，把查询到的信息返回给Page对象
        page=page(page,lqw);

        //返回结果
        ResponseResult responseResult=new PageResponseResult(dto.getPage(),dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());
        return responseResult;
    }
    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    /**
     * 发布新闻，修改新闻，保存。
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //1.参数校验
        if (dto==null||dto.getContent()==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //2.保存新闻或修改新闻
        WmNews wmNews = new WmNews();
        //属性Copy
        BeanUtils.copyProperties(dto,wmNews);
        //判断新闻有没有封面图片
        if (dto.getImages()!=null&&dto.getImages().size()>0){
            String imageStr = StringUtils.join(dto.getImages(), ",");
            wmNews.setImages(imageStr);
        }
        //如果当前封面类型为自动  -1
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            wmNews.setType(null);
        }
        //然后就保存或更新文章
        saveOrUpdateWmNews(wmNews);

        //判断是否为草稿，是草稿
        if (dto.getStatus().equals(WmNews.Status.NORMAL.getCode())){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }
        //不是草稿,保存新闻，保存新闻内容图片和素材之间的关系
        //获取新闻中的图片
        //返回的materials是新闻内容中所有图片的url的集合
        List<String> materials = ectractUrlInfo(dto.getContent());
        //保存【新闻【内容】图片】和【素材】的关系
        saveRelativeInfoForContent(materials,wmNews.getId());

        //不是草稿,保存新闻，保存【新闻【封面】图片】和【素材】之间的关系，如果是自动，那么就需要匹配封面图片。
        saveRelativeInfoForCover(dto,wmNews,materials);

        //自动审核新闻
        wmNewsAutoScanService.autoScanWmNews(wmNews.getId());

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     *  保存封面图片和素材之间的关系。
     *  如果用户选择自动，-1那么就需要根据新闻内容中的图片数量来进行判断是无图、单图、三图
     *  匹配的规则：
     *  1：如果内容图片大于等于1个，小于3个，单图，设置type=1
     *  2：如果内容图片大于等于3个，多图，设置type=3
     *  3：如果内容图片为0，没有内容图片，无图，设置type=0
     *
     * @param dto 前端传入的数据对象
     * @param wmNews 新闻对象
     * @param materials 新闻中所有的图片的url的集合
     */
    private void saveRelativeInfoForCover(WmNewsDto dto, WmNews wmNews, List<String> materials) {
        List<String> images = dto.getImages();

        //如果当前的封面类型设置为自动，那么就需要设置封面类型的数据
        if (dto.getType().equals(WemediaConstants.WM_NEWS_TYPE_AUTO)){
            //判断是无图、单图、三图
            if (materials.size()>=3){
                wmNews.setType(WemediaConstants.WM_NEWS_MANY_IMAGE);
                images = materials.stream().limit(3).collect(Collectors.toList());
            }else if (materials.size()>=1&&materials.size()<3){
                wmNews.setType(WemediaConstants.WM_NEWS_SINGLE_IMAGE);
                images = materials.stream().limit(1).collect(Collectors.toList());
            }else {
                wmNews.setType(WemediaConstants.WM_NEWS_NONE_IMAGE);
            }
            //修改文章
            if (images!=null&&images.size()>0){
                //设置封面图片
                wmNews.setImages(StringUtils.join(images,","));
            }
            updateById(wmNews);
        }
        //设置封面图片
        if (images!=null&&images.size()>0){
            saveRelativeInfo(images, wmNews.getId(), WemediaConstants.WM_COVER_REFERENCE);
        }
    }

    /**
     * 保存新闻内容中图片和素材之间的关系
     * @param materials
     * @param id
     */
    private void saveRelativeInfoForContent(List<String> materials, Integer id) {
        saveRelativeInfo(materials,id,WemediaConstants.WM_CONTENT_REFERENCE);
    }

    /**
     * 保存新闻图片和素材之间的关系，设置type是新闻封面还是新闻内容
     * @param materials 新闻中所有的图片的url的集合
     * @param newsId 新闻id
     * @param type 类型，0是内容图片，1是封面图片
     */
    private void saveRelativeInfo(List<String> materials, Integer newsId,Short type){
        if (materials!=null&&!materials.isEmpty()){
            //通过图片url获取素材的id
            List<WmMaterial> dbMaterials =wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                    .in(WmMaterial::getUrl,materials));
            //判断当前素材是否有效
            if (dbMaterials==null||dbMaterials.size()==0){
                //抛出自定义异常,告诉调用者，素材引用失效了，数据需要回滚
                throw  new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            //判断传入进来的materials素材列表长度如果和查询到的素材列表dbMaterials长度不一致，则抛异常
            if (dbMaterials.size()!=materials.size()){
                //抛出自定义异常,告诉调用者，素材引用失效了，数据需要回滚
                throw  new CustomException(AppHttpCodeEnum.MATERIASL_REFERENCE_FAIL);
            }
            //获取dbMaterials列表中所有的素材id，形成一个新的List集合

            /*ArrayList<Integer>  materialsIds= new ArrayList<>();
            Iterator<WmMaterial> iterator = dbMaterials.iterator();
            while (iterator.hasNext()){
                WmMaterial wmMaterial = iterator.next();
                Integer id = wmMaterial.getId();
                materialsIds.add(id);
            }*/
            //如果这段代码看不到，就使用上面被注释的代码
            List<Integer> materialsIds =
                    dbMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

            //批量保存，新闻中图片和素材的关系。
            wmNewsMaterialMapper.saveRelations(materialsIds,newsId,type);
        }
    }
    /**
     * 保存或更新新闻
     * @param wmNews
     */
    private void saveOrUpdateWmNews(WmNews wmNews) {
        //先补全属性
        Integer userId = WmThreadLocalUtil.getUser().getId();
        wmNews.setUserId(userId);
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);//默认就是上架
        if (wmNews.getId()==null){
            //保存
            save(wmNews);
        }else {
            //修改
            //删除新闻和素材之间的关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId,wmNews.getId()));
            //更新新闻
            updateById(wmNews);
        }
    }

    /**
     * 提取新闻内容中的图片信息
     * @param content
     * @return
     */
    private List<String> ectractUrlInfo(String content) {
        ArrayList<String> materials = new ArrayList<>();
        List<Map> maps = JSON.parseArray(content, Map.class);

        for (Map map:maps) {
            if (map.get("type").equals("image")){
                String imgUrl = (String)map.get("value");
                materials.add(imgUrl);
            }
        }
        return materials;
    }
}
